package com.dollar.ruyuan_juc.diy;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 实现一个 阻塞队列
 *
 * @param <E>
 */
public class MyArrayBlockingQueue<E> {

    private final int capacity; //队列容量
    private AtomicInteger count; //元素数量
    private AtomicInteger head; //poll索引
    private AtomicInteger tail; //put索引
    ReentrantLock lock = new ReentrantLock();
    Condition notEmpty = lock.newCondition();
    Condition notFull = lock.newCondition();
    //泛型数组无法直接创建，这里通过 Object[] 解决
    Object[] arr; //Channel(缓冲区)

    public MyArrayBlockingQueue(int capacity) {
        this.capacity = capacity;
        arr = new Object[capacity];
        head = new AtomicInteger(0);
        tail = new AtomicInteger(0);
        count = new AtomicInteger(0);
    }

    /**
     * 阻塞放
     *
     * @param e
     */
    public void put(E e) {
        lock.lock();
        try {
            //System.out.println("count: " + count.get());
            while (count.get() == capacity) {
                notFull.await();
            }
            arr[tail.get()] = e;
            //tail 后移
            tail.set(tail.incrementAndGet() % capacity);
            count.getAndIncrement();
            notEmpty.signalAll();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } finally {
            //保证锁释放
            lock.unlock();
        }
    }

    /**
     * 阻塞取
     *
     * @return
     */
    public E poll() {
        lock.lock();
        E e = null;
        try {
            while (count.get() == 0) {
                notEmpty.await();
            }
            e = (E) arr[head.get()];
            //head 后移
            head.set(head.incrementAndGet() % capacity);
            count.getAndDecrement();
            notFull.signalAll();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } finally {
            //保证锁释放
            lock.unlock();
        }
        return e;
    }

}
